package p3.enunciado;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Inet4Address;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

/**
 * Complementos de Informática. Práctica 3.
 * Cliente remoto.
 * @author JAPF
 *
 */
public class Cliente extends JFrame implements ActionListener {

    private static final long serialVersionUID = 4467223450798880000L;
    protected String hostIp;
    protected int hostPort;
    protected boolean connected;
    Socket cliente;
    protected BufferedReader socketReader;
    protected PrintWriter socketWriter;
    protected volatile int rC = 0;
    protected int numberOfTexts = 3;
    protected JScrollPane textPane;
    protected JTextArea textArea;
    protected JButton btConnect;
    protected JButton btRequestFile;
    protected JButton btDisconnect;
    protected JButton btClean;

    /**
     * Crea cliente remoto.
     * @param hostIp Dirección IP del servidor.
     * @param port   Puerto del servidor.
     */
    public Cliente(String hostIp, int port) {
        super("Cliente Remoto ");

        this.hostIp = hostIp;
        this.hostPort = port;

        JPanel textPanel = new JPanel();
        textPanel.setLayout(new BoxLayout(textPanel, BoxLayout.LINE_AXIS));

        textPanel.add(Box.createRigidArea(new Dimension(1, 0)));

        textArea = new JTextArea();
        textPane = new JScrollPane(textArea);
        textPanel.add(textPane);
        textPanel.add(Box.createRigidArea(new Dimension(1, 0)));

        JPanel btPanel = new JPanel();

        btConnect = new JButton("Connect ");
        btConnect.addActionListener(this);
        btRequestFile = new JButton("File ");
        btRequestFile.addActionListener(this);
        btDisconnect = new JButton("EoS ");
        btDisconnect.addActionListener(this);

        btClean = new JButton("Clean Text ");
        btClean.addActionListener(this);

        btPanel.add(btConnect);
        btPanel.add(btRequestFile);
        btPanel.add(btDisconnect);
        btPanel.add(btClean);

        getContentPane().add(btPanel, BorderLayout.NORTH);
        getContentPane().add(textPanel);

        setSize(390, 680);
        setVisible(true);
        validate();
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    }

    /**
     * Establece conexión con servidor.
     * @return socket cliente conectado al servidor.
     */
    public Socket establecerConexion() {
        Socket cliente = null;
        try {
            cliente = new Socket(Inet4Address.getLocalHost(), hostPort);
        } catch (UnknownHostException uhe) {
            System.out.println("establecerConexion: " + uhe.getMessage());
        } catch (IOException ioe) {
            System.out.println("establecerConexion: " + ioe.getMessage());
        }
        return cliente;
    }

    /**
     * Solicita un servicio según el botón pulsado.
     */
    @Override
    public void actionPerformed(ActionEvent ae) {

        // conexión CON EL SERVIDOR.................................................
        if (ae.getSource() == btConnect) {
            System.out.println();
            System.out.println("Cliente. Pidiendo conexión. ");
            System.out.println();
            textArea.append("-------------------------\n");
            textArea.append("Cliente. Pidiendo conexión.\n");
            textArea.append("-------------------------\n");

            // Establece conexión con el servidor.
            cliente = establecerConexion();

            System.out.println("Cliente. conexión establecida. ");
            textArea.append("-------------------------\n");
            textArea.append("Cliente. conexión establecida.\n");
            textArea.append("-------------------------\n");

            // Inicializa flujo de salida para enviar peticiones de servicio.
            try {
                socketWriter = new PrintWriter(cliente.getOutputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
            connected = true;

            // Crea y arranca un hilo que recibe las respuestas del servidor.
            try {
                new Thread(new SocketReader(cliente)).start();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        // PETICIÓN DE FICHERO.................................................
        if (ae.getSource() == btRequestFile) {
            if (!connected) {
                return;
            }
            System.out.println();
            System.out.println("Cliente. Pidiendo fichero Ej" + (rC + 1));
            System.out.println();

            textArea.append("-------------------------\n");
            textArea.append("Cliente. Pidiendo fichero Ej" + (rC + 1) + "\n");
            textArea.append("-------------------------\n");

            // Construye petición.
            String request = Servidor.SendFile + "," + "Ej" + (rC + 1) + ".txt";

            // Envía petición.
            socketWriter.println(request);
            socketWriter.flush();
            rC = (rC + 1) % numberOfTexts;
        }

        // PETICION DE FIN DE CONEXION...........................................
        if (ae.getSource() == btDisconnect) {
            if (!connected) {
                return;
            }
            System.out.println();
            System.out.println("Cliente. Fin de conexión");
            System.out.println();

            textArea.append("\n-------------------------\n");
            textArea.append("Solicitando fin de conexión \n");
            textArea.append("\n-------------------------\n");

            // Construye petición. 
            String request = Servidor.CloseConnection;

            // Manda petición.
            socketWriter.println(request);
            socketWriter.flush();
        }

        // Limpia área de texto....................................................
        if (ae.getSource() == btClean) {
            textArea.setText(null);
        }
    }

    /**
     * Pide fichero, recibe su contenido y lo muestra a medida que
     * lo recibe. 
     * @author JAPF
     *
     */
    public class SocketReader implements Runnable {

        Socket s;
        BufferedReader socketReader;
        boolean stop;

        /**
         * Lee los datos que envía el servidor y los muestra en un área de texto.
         * @param cliente socket ligado a la conexión cliente-servidor.
         * @throws IOException
         */
        public SocketReader(Socket cliente) throws IOException {
            s = cliente;
            socketReader = new BufferedReader(new InputStreamReader(s.getInputStream()));
        }

        @Override
        public void run() {
            System.out.println("Cliente. SocketReader. Hilo empezado");

            String linea = null;
            while (!stop) {
                try {
                    linea = socketReader.readLine();
                    String[] fields = linea.split(",");
                    if (fields[0] == Servidor.CloseConnection) {
                        stop = true;
                    }
                } catch (SocketException e) {
                    e.printStackTrace();
                    return;
                } catch (IOException e) {
                    e.printStackTrace();
                }
                textArea.append(linea + "\n");
                System.out.println(linea);
            }
            try {
                socketReader.close();
                s.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println("Cliente. SocketReader. Hilo terminado");
        }
    }

    public static void main(String[] args) {
        new Cliente("127.0.0.1", 3000);
    }
}
